import type { EmbeddedRestDatasource } from "entities/Datasource";
import type { DynamicPath } from "utils/DynamicBindingUtils";
import _ from "lodash";
import type { LayoutOnLoadActionErrors } from "constants/AppsmithActionConstants/ActionConstants";
import type { EventLocation } from "ee/utils/analyticsUtilTypes";
import type { ActionParentEntityTypeInterface } from "ee/entities/Engine/actionHelpers";
import {
  PluginPackageName,
  PluginType,
  type Plugin,
  type PluginName,
} from "../Plugin";
import type { ActionRunBehaviourType } from "PluginActionEditor/types/PluginActionTypes";

export enum PaginationType {
  NONE = "NONE",
  PAGE_NO = "PAGE_NO",
  URL = "URL",
  CURSOR = "CURSOR",
}

// Used for analytic events
export enum ActionCreationSourceTypeEnum {
  SELF = "SELF",
  GENERATE_PAGE = "GENERATE_PAGE",
  ONE_CLICK_BINDING = "ONE_CLICK_BINDING",
  CLONE_PAGE = "CLONE_PAGE",
  FORK_APPLICATION = "FORK_APPLICATION",
  COPY_ACTION = "COPY_ACTION",
}

// Used for analytic events
export enum ActionExecutionContext {
  SELF = "SELF",
  ONE_CLICK_BINDING = "ONE_CLICK_BINDING",
  GENERATE_CRUD_PAGE = "GENERATE_CRUD_PAGE",
  CLONE_PAGE = "CLONE_PAGE",
  FORK_TEMPLATE_PAGE = "FORK_TEMPLATE_PAGE",
  PAGE_LOAD = "PAGE_LOAD",
  EVALUATION_ACTION_TRIGGER = "EVALUATION_ACTION_TRIGGER",
  REFRESH_ACTIONS_ON_ENV_CHANGE = "REFRESH_ACTIONS_ON_ENV_CHANGE",
  PAGE_UNLOAD = "PAGE_UNLOAD",
}

export interface KeyValuePair {
  key?: string;
  value?: unknown;
}

export interface LimitOffset {
  limit: Record<string, unknown>;
  offset: Record<string, unknown>;
}
export interface SelfReferencingData {
  limitBased?: LimitOffset;
  curserBased?: {
    previous?: LimitOffset;
    next?: LimitOffset;
  };
}

export interface ActionConfig {
  timeoutInMillisecond?: number;
  paginationType?: PaginationType;
  formData?: Record<string, unknown>;
  pluginSpecifiedTemplates?: KeyValuePair[];
  path?: string;
  queryParameters?: KeyValuePair[];
  selfReferencingData?: SelfReferencingData;
}

export interface Property {
  key: string;
  value: string;
}

export interface BodyFormData {
  editable: boolean;
  mandatory: boolean;
  description: string;
  key: string;
  value?: string;
  type: string;
}

export interface AutoGeneratedHeader {
  key: string;
  value: string;
  isInvalid: boolean;
}

export interface ApiActionConfig extends Omit<ActionConfig, "formData"> {
  headers: Property[];
  autoGeneratedHeaders?: AutoGeneratedHeader[];
  httpMethod: string;
  httpVersion: string;
  path?: string;
  // TODO: Fix this the next time the file is edited
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  body?: JSON | string | Record<string, any> | null;
  encodeParamsToggle: boolean;
  queryParameters?: Property[];
  bodyFormData?: BodyFormData[];
  formData: Record<string, unknown>;
  query?: string | null;
  variable?: string | null;
}

export interface QueryActionConfig extends ActionConfig {
  body?: string;
}

// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const isStoredDatasource = (val: any): val is StoredDatasource => {
  if (!_.isObject(val)) return false;

  if (!("id" in val)) return false;

  return true;
};
export interface StoredDatasource {
  name?: string;
  id: string;
  pluginId?: string;
  datasourceConfiguration?: { url?: string };
}

export interface VisualizationElements {
  css: string;
  js: string;
  html: string;
}

export interface BaseAction {
  id: string;
  baseId: string;
  name: string;
  workspaceId: string;
  applicationId: string;
  pageId: string;
  collectionId?: string;
  pluginId: string;
  runBehaviour: ActionRunBehaviourType;
  dynamicBindingPathList: DynamicPath[];
  isValid: boolean;
  invalids: string[];
  jsonPathKeys: string[];
  cacheResponse: string;
  confirmBeforeExecute?: boolean;
  // TODO: Fix this the next time the file is edited
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  eventData?: any;
  messages: string[];
  userPermissions?: string[];
  errorReports?: Array<LayoutOnLoadActionErrors>;
  isPublic?: boolean;
  packageId?: string;
  moduleId?: string;
  moduleInstanceId?: string;
  workflowId?: string;
  contextType?: ActionParentEntityTypeInterface;
  // This is used to identify the main js collection of a workflow
  // added here to avoid ts error in entitiesSelector file, in practice
  // will always be undefined for non js actions
  isMainJSCollection?: boolean;
  source?: ActionCreationSourceTypeEnum;
  visualization?: {
    result: VisualizationElements;
  };
  isDirtyMap?: {
    SCHEMA_GENERATION: boolean;
  };
}

interface BaseApiAction extends BaseAction {
  pluginType: PluginType.API;
  actionConfiguration: ApiActionConfig;
}
export interface SaaSAction extends BaseAction {
  pluginType: PluginType.SAAS;
  // TODO: Fix this the next time the file is edited
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  actionConfiguration: any;
  datasource: StoredDatasource;
}
export interface RemoteAction extends BaseAction {
  pluginType: PluginType.REMOTE;
  // TODO: Fix this the next time the file is edited
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  actionConfiguration: any;
  datasource: StoredDatasource;
}
export interface AIAction extends BaseAction {
  pluginType: PluginType.AI;
  // TODO: Fix this the next time the file is edited
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  actionConfiguration: any;
  datasource: StoredDatasource;
}
export interface InternalAction extends BaseAction {
  pluginType: PluginType.INTERNAL;
  // TODO: Fix this the next time the file is edited
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  actionConfiguration: any;
  datasource: StoredDatasource;
}

export interface EmbeddedApiAction extends BaseApiAction {
  datasource: EmbeddedRestDatasource;
}

export interface StoredDatasourceApiAction extends BaseApiAction {
  datasource: StoredDatasource;
}

export type ApiAction = EmbeddedApiAction | StoredDatasourceApiAction;

export interface QueryAction extends BaseAction {
  pluginType: PluginType.DB;
  pluginName?: PluginName;
  actionConfiguration: QueryActionConfig;
  datasource: StoredDatasource;
}

export interface ActionViewMode {
  id: string;
  baseId: string;
  name: string;
  pageId: string;
  jsonPathKeys: string[];
  confirmBeforeExecute?: boolean;
  timeoutInMillisecond?: number;
}

export interface ExternalSaasAction extends BaseAction {
  pluginType: PluginType.EXTERNAL_SAAS;
  // TODO: Fix this the next time the file is edited
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  actionConfiguration: any;
  datasource: StoredDatasource;
}

export type Action =
  | ApiAction
  | QueryAction
  | SaaSAction
  | RemoteAction
  | AIAction
  | InternalAction
  | ExternalSaasAction;

export enum SlashCommand {
  NEW_API,
  NEW_QUERY,
  NEW_INTEGRATION,
  ASK_AI,
}

export interface SlashCommandPayload {
  actionType: SlashCommand;
  callback?: (binding: string) => void;
  // TODO: Fix this the next time the file is edited
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  args: any;
}

export function isAPIAction(action: Action): action is ApiAction {
  return action.pluginType === PluginType.API;
}

export function isQueryAction(action: Action): action is QueryAction {
  return action.pluginType === PluginType.DB;
}

export function isSaaSAction(action: Action): action is SaaSAction {
  return action.pluginType === PluginType.SAAS;
}

export function isAIAction(action: Action): action is AIAction {
  return action.pluginType === PluginType.AI;
}

export function getGraphQLPlugin(plugins: Plugin[]): Plugin | undefined {
  return plugins.find((p) => p.packageName === PluginPackageName.GRAPHQL);
}

export function getAppsmithAIPlugin(plugins: Plugin[]): Plugin | undefined {
  return plugins.find((p) => p.packageName === PluginPackageName.APPSMITH_AI);
}

export function getAppsmithAgentPlugin(plugins: Plugin[]): Plugin | undefined {
  return plugins.find(
    (p) => p.packageName === PluginPackageName.APPSMITH_AGENT,
  );
}

export function isGraphqlPlugin(plugin: Plugin | undefined) {
  return plugin?.packageName === PluginPackageName.GRAPHQL;
}

export function isRESTAPIPlugin(plugin: Plugin | undefined) {
  return plugin?.packageName === PluginPackageName.REST_API;
}

export const SCHEMA_SECTION_ID = "t--api-right-pane-schema";

export interface CreateApiActionDefaultsParams {
  apiType: string;
  from?: EventLocation;
  newActionName?: string;
}

export interface CreateActionDefaultsParams {
  datasourceId: string;
  from?: EventLocation;
  newActionName?: string;
  queryDefaultTableName?: string;
}
